    #pragma once
    #include <iostream>
    #include <string>
    #include <unistd.h>
    #include <queue>
    #include <pthread.h>
    #include "cond.hpp"
    #include "Mutex.hpp"
    using namespace std;
    using namespace ve;
    using namespace VE;

    const int maxcap = 5; // 最大容量

    template <class t>
    class blockqueue
    {
    private:
        queue<t> _bq; // 队列,这个队列就是临界资源，需要上锁
        int _cap;     // 容量

        Mutex _mutex;
        Cond _full_cond;
        Cond _empty_cond;
        int _csleep_num;
        int _psleep_num;

    public:
        bool isfull()
        {
            return _bq.size() >= _cap;
        }
        bool isempty()
        {
            return _bq.size() <= 0;
        }
        blockqueue() : _cap(maxcap), _csleep_num(0), _psleep_num(0)
        {
        }
        void push(const t &val)
        {
            {
                lockguard lg(_mutex);
                while (isfull()) // 一定要使用while，因为可能存在线程的伪唤醒：在这个例子下就是下面的 pthread_cond_wait(_full_cond, &_lock);被唤醒时可能会有多个线程被唤醒，如果用if，那么多个线程就没有再判断if中的条件就唤醒执行了。
                {
                    _psleep_num++;           // 等待
                    _full_cond.wait(_mutex); // 让生产者线程等待。
                                            // 可见我们对于线程的等待控制一定是在临界区中的，所以就能理解第二个参数为什么是lock了，因为我们让线程在条件变量下等待前需要将锁解开。
                                            // 当当前线程需要唤醒时（被唤醒时也一定是在临界区内部），就需要先将锁加上
                    _psleep_num--;
                }

                _bq.push(val);

                if (_csleep_num > 0)
                {
                    cout << "唤醒消费者 " << endl;
                    _empty_cond.signal();
                }
                // 将解锁放到唤醒后面是可以的，因为当你唤醒时还没有解锁此时线程不是在条件变量下等待了
                // 而是在锁下等待，然后下一行将锁释放，刚被唤醒的线程就能运行了。
            }
        }
        t pop()
        {
            t data;
            {
                lockguard lg(_mutex);
                while (isempty()) // 需要进行等待
                {
                    _csleep_num++;
                    _empty_cond.wait(_mutex);
                    _csleep_num--;
                }

                data = _bq.front();
                _bq.pop();

                if (_psleep_num > 0)
                {
                    cout << "唤醒生产者 " << endl;
                    _full_cond.signal();
                }
            }
            return data;
        }
    };